/*
 
 Copyright (C) 2009 Id Software, Inc.
 
 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 */

#include "../wolfiphone.h"
#import "../koth.h"
#import "../jwglut/jwglut.h"
#import "../iphone/wolf3dAppDelegate.h"
#import "../iphone/EAGLView.h"
#import "../koth/kothConstants.h"
#import <QuartzCore/CADisplayLink.h>


currentMap_t currentMap;

vec3_t	vnull = { 0, 0, 0 };

int		iphoneFrameNum;
int		intermissionTriggerFrame;
int		slowAIFrame;

// console mode
int consoleActive;

// the native iPhone code should set the following each frame:
int	numTouches;
int	touches[5][2];	// [0] = x, [1] = y in landscape mode, raster order with y = 0 at top
int swipe[2] = {0}; // [0] = h, [1] = v.
float	tilt;		// -1.0 to 1.0
float	tiltPitch;

#define MAX_TILT_HISTORY 64
float	tiltHistory[MAX_TILT_HISTORY][4];
int		tiltHistoryNum;

// so we can detect button releases
int	numPrevTouches;
int prevTouches[5][2];

texture_t *numberPics[10];

char *mugshotnames[ NUM_MUGSHOTS ] =
{
"iphone/FACE1APIC.tga",
"iphone/FACE1BPIC.tga",
"iphone/FACE1CPIC.tga",

"iphone/FACE2APIC.tga",
"iphone/FACE2BPIC.tga",
"iphone/FACE2CPIC.tga",

"iphone/FACE3APIC.tga",
"iphone/FACE3BPIC.tga",
"iphone/FACE3CPIC.tga",

"iphone/FACE4APIC.tga",
"iphone/FACE4BPIC.tga",
"iphone/FACE4CPIC.tga",

"iphone/FACE5APIC.tga",
"iphone/FACE5BPIC.tga",
"iphone/FACE5CPIC.tga",

"iphone/FACE6APIC.tga",
"iphone/FACE6BPIC.tga",
"iphone/FACE6CPIC.tga",

"iphone/FACE7APIC.tga",
"iphone/FACE7BPIC.tga",
"iphone/FACE7CPIC.tga",

"iphone/FACE8APIC.tga",
"iphone/GOTGATLINGPIC.tga"		
};

int damageflash;
int bonusFrameNum;
int attackDirTime[2];

logTime_t	loggedTimes[MAX_LOGGED_TIMES];	// indexed by iphoneFrameNum

/*
 ==================
 iphoneActivateConsole
 
 ==================
 */
void iphoneActivateConsole() {
	extern float scr_conlines;
	scr_conlines = 0.5f;
	consoleActive = 1;
	
	// draw a frame immediately, because the UIKit takes
	// a long time to bring up the keyboard
	iphoneFrame();
}

/*
 ==================
 iphoneDeactivateConsole
 
 ==================
 */
void iphoneDeactivateConsole() {
	extern float scr_conlines;
	scr_conlines = 0.0f;
	consoleActive = 0;
}

/*
 ==================
 iphoneExecuteConsoleCommand
 
 ==================
 */
void iphoneExecuteCommandLine() {
	char buf[256];
	strcpy( buf, SysIPhoneGetConsoleTextField() );
	
	Com_Printf( "%s\n", buf );
	Cmd_ExecuteString( buf );
	SysIPhoneSetConsoleTextField( "" );
}



/*
 ==================
 iphoneSavePrevTouches
 
 ==================
 */
void iphoneSavePrevTouches() {
	numPrevTouches = numTouches;
	memcpy( prevTouches, touches, sizeof( prevTouches ) );
#if 0	
	// display the touch locations
	for ( int i = 0 ; i < numTouches ; i++ ) {
		int	w = 32;
		iphoneDrawPic( touches[i][0] - w/2, touches[i][1] - w/2, w, w, "iphone/diractional_02.tga" );
	}
#endif
}

/*
 ==================
 iphoneCenterText
 
 Returns the width in pixels
 ==================
 */
extern font_t *myfonts[ 1 ];
int iphoneCenterText( int x, int y, const char *str ) {
	int l = strlen( str );
	int	i;
	font_t *myfont = myfonts[0];
	int		scale;
	int		step = 10;
	
	scale = 16;
	
	x -= l * step / 2;
	
	R_Bind( myfont->texfont->texnum );
	pfglBegin( GL_QUADS );

	for ( i = 0 ; i < l ; i++, x += step ) { 
		int	row, col; 
		float frow, fcol;
		int	num = str[i];
		
		if ( num == ' ' ) {
			continue;
		}
		
		row = (num >> 4) - 2;
		col = num & 15;
		
		frow = row * myfont->hFrac;
		fcol = col * myfont->wFrac;
	
		pfglTexCoord2f( fcol, frow );							
		pfglVertex2i( x, y );
		
		pfglTexCoord2f( fcol+myfont->wFrac, frow );					
		pfglVertex2i( x+scale, y );
		
		pfglTexCoord2f( fcol+myfont->wFrac, frow+myfont->hFrac );	
		pfglVertex2i( x+scale, y+scale );
		
		pfglTexCoord2f( fcol, frow+myfont->hFrac );
		pfglVertex2i( x, y+scale );			
	}
	
	pfglEnd();
	
	return l * step;
}


/*
 ==================
 TouchDown
 
 Checks all touches against a square
 ==================
 */
int	TouchDown( int x, int y, int w, int h ) {
	int	i;
	for ( i = 0 ; i < numTouches ; i++ ) {
		if ( touches[i][0] >= x && touches[i][1] >= y
			&& touches[i][0] < x + w && touches[i][1] < y + h ) {
			return 1;
		}
	}
	if(i == 2) {
		[[JWPicker picker] clearSelection];
	}
	return 0;
}

/*
 ==================
 TouchReleased
 
 Perform an action when released in the box.
 If not down this frame, but down the previous frame, it is released
 ==================
 */
int	TouchReleased( int x, int y, int w, int h ) {
	int	i;
	int	downPrev = 0;
	int downNow = 0;
	
	for ( i = 0 ; i < numPrevTouches ; i++ ) {
		if ( prevTouches[i][0] >= x && prevTouches[i][1] >= y
			&& prevTouches[i][0] < x + w && prevTouches[i][1] < y + h ) {
			downPrev = 1;
			break;
		}
	}
	
	// see if not down this frame
	for ( i = 0 ; i < numTouches ; i++ ) {
		if ( touches[i][0] >= x && touches[i][1] >= y
			&& touches[i][0] < x + w && touches[i][1] < y + h ) {
			downNow = 1;
			break;
		}
	}
	
	if ( !downPrev ) {
		if ( downNow ) {
			//Sound_StartLocalSound( "iphone/bdown_01.wav" );
		}
		// wasn't down the previous frame
		return 0;
	}
	
	if ( downNow ) {
		// still down
		return 0;
	}
	
	if ( numTouches == numPrevTouches ) {
		// finger dragged off
		//Sound_StartLocalSound( "iphone/baborted_01.wav" );
		return 0;
	}
	
	// released
	//Sound_StartLocalSound( "iphone/baction_01.wav" );
	return 1;
}

/*
 ==================
 iphoneRotateForLandscape
 
 ==================
 */
void iphoneRotateForLandscape() {
	if ( revLand->value ) {
		// reverse landscape mode
		pfglRotatef( -90, 0, 0, 1 );
	} else {
		pfglRotatef( 90, 0, 0, 1 );
	}
}

/*
 ==================
 iphoneSet2D
 
 ==================
 */
void iphoneSet2D( void ) {
	pfglViewport( 0,0, 480, 320 );
	pfglMatrixMode( GL_MODELVIEW );
    pfglLoadIdentity();
	pfglDisable( GL_DEPTH_TEST );
	pfglDisable( GL_CULL_FACE );
	pfglEnable( GL_BLEND );
	pfglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
	pfglDisable( GL_ALPHA_TEST );
	pfglColor4f( 1,1,1,1 );
	
	pfglMatrixMode( GL_PROJECTION );
    pfglLoadIdentity();
	iphoneRotateForLandscape();
	pfglOrtho( 0, 480, 320, 0, -99999, 99999 );
}


/*
 ==================
 DeadBandAdjust
 
 Compresses the 0.0 - 1.0 range into deadband - 1.0
 ==================
 */
float DeadBandAdjust( float f, float deadBand ) {
	if ( f < 0 ) {
		return -DeadBandAdjust( -f, deadBand );
	}
	if ( f > 1.0 ) {
		return 1.0;
	}
	if ( f < deadBand ) {
		return 0;
	}
	return (f-deadBand) / (1.0 - deadBand);
}

#if 0
/*
==================
AxisHit

Returns a -1 to 1 range

If activeFraction is less than 1.0, the range will clamp
to the limits before the edge of the box is hit.
==================
*/
float	AxisHit( hudPic_t *hud ) {
	int x = hud->x;
	int y = hud->y;
	int width = hud->width;
	int height = hud->width;
	float activeFraction = 0.8f;
	int	i;
	int isXaxis = ( hud != &huds.forwardStick );
	
	if ( hud->hudFlags & HF_DISABLED ) {
		return 0;
	}
	
	// allow the touches to go outside the indicated bounds with clamping
	x += width / 2;
	y += height / 2;
	width *= 2;
	activeFraction *= 0.5f;
	
	// if the axis is not paired with another, leave it skinnier along the axis
	if ( hud == &huds.sideStick && huds.forwardStick.x == hud->x && huds.forwardStick.y == hud->y ) {
		height *= 2;
	}
	if ( hud == &huds.turnStick && huds.forwardStick.x == hud->x && huds.forwardStick.y == hud->y ) {
		height *= 2;
	}
	if ( hud == &huds.forwardStick ) {
		// don't bother checking for a skinny forwardStick
		height *= 2;
	}

	x -= width / 2;
	y -= height / 2;
	
	for ( i = 0 ; i < numTouches ; i++ ) {
		if ( touches[i][0] >= x && touches[i][1] >= y
			&& touches[i][0] < x + width && touches[i][1] < y + height ) {
				float	f;
				if ( isXaxis ) {
					f = (float)( touches[i][0] - x ) / width * 2.0f - 1.0f;
				} else {
					f = (float)( touches[i][1] - y ) / height * 2.0f - 1.0f;
				}
				f /= activeFraction;
				if ( f > 1.0f ) {
					f = 1.0f;
				} else if ( f < -1.0f ) {
					f = -1.0f;
				}
				if ( f > -stickDeadBand->value && f < stickDeadBand->value ) {
					f = 0;
				}
				return f;
		}
	}
	return 0;
}
#endif

void iphoneTouchEvent( int _numTouches, int _touches[16] ) {
	numTouches = _numTouches;
	for ( int i = 0 ; i < numTouches ; i++ ) {
		if ( revLand->value ) {
			touches[i][0] = _touches[i*2+1];
			touches[i][1] = 319 - _touches[i*2+0];
		} else {
			touches[i][0] = 479 - _touches[i*2+1];
			touches[i][1] = _touches[i*2+0];
		}
	}
}

void iphoneSwipeEvent(int horizontal, int vertical)
{
	// Rotate player proportional to horizontal, and adjust azimuth proportional to vertical.
	//NSLog(@"Swipe: (H: %d, V: %d)", horizontal, vertical);
	swipe[0] = horizontal * kothSwipeSensitivity;
	swipe[1] = vertical * kothSwipeSensitivity;
}

void iphoneCheckForLandscapeReverse() {
	static int reverseCount;
	
	// if we stay significantly negative for half a second, flip orientation
	if ( tiltPitch < -0.35 ) {
		if ( ++reverseCount > 10 ) {
			Cvar_SetValue( revLand->name, !revLand->value );
			SysIPhoneSetUIKitOrientation( revLand->value );
		}
	} else {
		reverseCount = 0;
	}
}

void iphoneTiltEvent( float *tilts ) {
	int		i;
	int		j;
	int		c;
	float	sum[3];
	static float prevTime;

	if ( revLand->value ) {
		tilts[1] = -tilts[1];
		tilts[0] = -tilts[0];
	}

	c = tiltAverages->value;
	if ( c < 1 ) {
		c = 1;
	} else if ( c > MAX_TILT_HISTORY ) {
		c = MAX_TILT_HISTORY;
	}
	
	// acc[0] - [2] are accelerometer values, ax[3] is the timestamp
	for ( i = 0 ; i < 3 ; i++ ) {
		tiltHistory[tiltHistoryNum&(MAX_TILT_HISTORY-1)][i] = tilts[i];
		sum[i] = 0;
		for ( j = 0 ; j < c ; j++ ) {
			sum[i] += tiltHistory[(tiltHistoryNum-j)&(MAX_TILT_HISTORY-1)][i];
		}
		sum[i] /= c;
	}
	// save the timestamp for analysis
	tiltHistory[tiltHistoryNum&(MAX_TILT_HISTORY-1)][3] = tilts[3] - prevTime;	
	prevTime = tilts[3];
	tiltHistoryNum++;
	
	tilt = sum[1];
	tiltPitch = sum[0];
//	Com_Printf( "%4.2f %4.2f %4.2f\n", tilts[0], tilts[1], tilts[2] );
}

void ShowTilt() {
	int	i;
	int	axis = (int)showTilt->value;
	colour4_t fillColor = { 255, 0, 0, 255 };
	colour4_t whiteColor = { 255, 255, 255, 255 };
	colour4_t nowColor = { 0, 255, 0, 255 };
	float	x;
	
	if ( axis < 0 || axis > 2 ) {
		return;
	}
	for ( i = 0 ; i < MAX_TILT_HISTORY ; i++ ) {
		x = tiltHistory[(tiltHistoryNum-1-i)&(MAX_TILT_HISTORY-1)][axis] * ( 10 / 0.018168604 );
		if ( x < 0 ) {
			R_Draw_Fill( 240 + x, i*4, -x, 4, fillColor );
		} else if ( x > 0 ) {
			R_Draw_Fill( 240, i*4, x, 4, fillColor );
		}
	}
	x = tilt * ( 10 / 0.018168604 );
	if ( x < 0 ) {
		R_Draw_Fill( 240 + x, i*4, -x, 4, nowColor );
	} else if ( x > 0 ) {
		R_Draw_Fill( 240, i*4, x, 4, nowColor );
	}
	R_Draw_Fill( 240, 0, 1, MAX_TILT_HISTORY*4, whiteColor );
}

void ShowTime() {
	int	i;
	if ( !showTime->value ) {
		return;
	}
	colour4_t frameColor = { 0, 0, 255, 255 };
	colour4_t swapColor = { 255, 0, 0, 255 };
	colour4_t activeColor = { 0, 255, 0, 255 };
	
	for ( i = 1 ; i < 30 ; i++ ) {
		logTime_t *lt = &loggedTimes[(iphoneFrameNum - i ) & (MAX_LOGGED_TIMES-1)];
		logTime_t *ltp = &loggedTimes[(iphoneFrameNum - i - 1 ) & (MAX_LOGGED_TIMES-1)];
		int	frameTime = lt->enterFrame - ltp->enterFrame;
		int	swapTime = lt->afterSwap - lt->beforeSwap;
		int	activeTime = lt->beforeSwap - lt->enterFrame;
		R_Draw_Fill( 0, i * 4, frameTime * 8, 2, frameColor );
		R_Draw_Fill( frameTime * 8 - swapTime * 8, i * 4, swapTime * 8, 2, swapColor );
		R_Draw_Fill( 0, i * 4, activeTime * 8, 2, activeColor );
	}
}


/*
==================
CreateIphoneUserCmd

Build the movement, angles, and buttons for a frame of action:

Player.position.angle
Player.cmd.buttons
Player.cmd.forwardMove
Player.cmd.sideMove
==================
*/
PRIVATE void CreateIphoneUserCmd()
{
	float	stickTurnValue;
	float	stickMoveValue;
	
	stickTurnValue = stickTurnBase->value + stickTurnScale->value * sensitivity->value;
	stickMoveValue = stickMoveBase->value + stickMoveScale->value * sensitivity->value;
	
	usercmd_t *cmd = &Player.cmd;
	memset( cmd, 0, sizeof( *cmd ) );
#if 0		   
	if ( TouchDown( huds.fire.x, huds.fire.y, huds.fire.width, huds.fire.height ) ) {
		cmd->buttons |= BUTTON_ATTACK;
	}
	if ( tiltFire->value > 0 && tiltPitch < tiltFire->value ) {
		cmd->buttons |= BUTTON_ATTACK;
	}

	// tapping the weapon issues the nextWeapon impulse
	if ( TouchReleased( 240 - 40, 320 - 80 - 64, 80, 64 ) ) {
		cmd->buttons |= BUTTON_CHANGE_WEAPON;
	}
	
	cmd->forwardmove = -stickMoveValue * AxisHit( &huds.forwardStick );
	cmd->sidemove = stickMoveValue * AxisHit( &huds.sideStick );
#endif
	//int delta = -stickTurnValue * AxisHit( &huds.turnStick );
	//NSLog(@"%d", delta);
	//Player.position.angle += -stickTurnValue * AxisHit( &huds.turnStick );
	Player.position.angle -= swipe[0];
	Player.position.azimuth += swipe[1];
	
	/*
	if(Player.position.azimuth < -30) {
		Player.position.azimuth = -30;
	} else if(Player.position.azimuth > 60) {
		Player.position.azimuth = 60;
	}
	*/

	// accelerometer tilting
	cmd->sidemove += tiltMove->value * DeadBandAdjust( tilt, tiltDeadBand->value );
	Player.position.angle -= tiltTurn->value * DeadBandAdjust( tilt, tiltDeadBand->value );
	
	// always use
	if ( iphoneFrameNum & 1 ) {
		cmd->buttons |= BUTTON_USE;
	}
}


#if 0
/*
==================
iphoneHighlightPicWhenTouched

Draw transparent except when touched
=================
*/
void iphoneHighlightPicNumWhenTouched( int x, int y, int w, int h, int glTexNum ) {
	if ( TouchDown( x, y, w, h ) ) {
		pfglColor4f(1,1,1,1);
	} else {
		pfglColor4f(1,1,1,0.5);
	}
	iphoneDrawPicNum( x, y, w, h, glTexNum );
	pfglColor4f(1,1,1,1);
}

/*
 ==================
 iphoneDrawWeapon
 
 ==================
 */
void iphoneDrawWeapon( void ) {
	char name[ 32 ];
	texture_t *tex;	
	static int w = 128;
	static int h = 128;
	int x = (viddef.width - w ) >> 1;
	int y = viddef.height - 80 - h;
	int	frame;
	
	if ( gunFrame->value ) {
		// screenshots look better with the muzzle flash
		frame = Player.weapon * 4 + gunFrame->value + SPR_KNIFEREADY;
	} else {
		frame = Player.weapon * 4 + Player.weaponframe + SPR_KNIFEREADY;
	}
	
	my_snprintf( name, sizeof( name ), "%s/%d.tga", spritelocation, frame);
	tex = TM_FindTexture( name, TT_Pic );

	R_Bind( tex->texnum );

	pfglBegin( GL_QUADS );
	
	pfglTexCoord2f( 0.01f, 0.01f );	pfglVertex2i( x, y );
	pfglTexCoord2f( 0.99f, 0.01f );	pfglVertex2i( x + w, y );
	pfglTexCoord2f( 0.99f, 0.99f );	pfglVertex2i( x + w, y + h );
	pfglTexCoord2f( 0.01f, 0.99f );	pfglVertex2i( x, y + h );
	
	pfglEnd();
}

/*
 ==================
 iphoneDrawNumber
 
 x is the midpoint, y is the top
 ==================
 */
void iphoneDrawNumber( int x, int y, int number, int charWidth, int charHeight ) {	
	texture_t *tex;
	int i;
	char string[ 20 ];
	W32 length;
	float charStep = charWidth * 0.8;	// trim off extra width

	if ( number < 0 ) {
		number = 0;
	}
	my_snprintf( string, sizeof( string ), "%d", number );
	length = strlen( string );
	
	x -= length * charStep / 2;
	
	for( i = 0 ; i < length ; i++ ) {
		int digit = string[i] - '0';
		tex = numberPics[digit];
		R_Bind( tex->texnum );
		pfglBegin( GL_QUADS );
		
		pfglTexCoord2f( 0, 0 );	pfglVertex2i( x, y );
		pfglTexCoord2f( 1, 0 );	pfglVertex2i( x+charWidth, y );
		pfglTexCoord2f( 1, 1 );	pfglVertex2i( x+charWidth, y+charHeight );
		pfglTexCoord2f( 0, 1 );	pfglVertex2i( x, y+charHeight );
		
		pfglEnd();
		x += charStep;
	}
}


/*
 ==================
 iphoneDrawFace
 
 ==================
 */
void iphoneDrawFace() {
	int i;
	int w = 64;
	int h = 80;
	int x = (viddef.width - w ) >> 1;
	int y = viddef.height - h;
	const char *pic;

	// solid background
	iphoneDrawPic( 240 - 64, 320 - 80, 128, 80, "iphone/status_hud.tga" );

	// keys on the side
	if( Player.items & ITEM_KEY_1 ) {
		iphoneDrawPic( 240-64, 320-72, 32, 64, "iphone/gold_key.tga" );
	}
	
	if( Player.items & ITEM_KEY_2 ) {
		iphoneDrawPic( 240+32, 320-72, 32, 64, "iphone/silver_key.tga" );
	}
	
	
	// decide on the face
	//Player.facecount += tics;
	if ( Player.face_gotgun && Player.facecount > 0 ) {
		// gotgun will set facecount to a negative number initially, go back
		// to normal face with random look after expired.
		Player.face_gotgun = false;
	}
	if( Player.facecount > US_RndT() )
	{
		Player.face_gotgun = Player.face_ouch = false;
		Player.faceframe = US_RndT() >> 6;
		if( Player.faceframe == 3 )
		{
			Player.faceframe = 0;
		}
		
		Player.facecount = 0;
	}

	if( Player.health )
	{
		if( Player.face_gotgun )
		{
			pic = mugshotnames[ 22 ];
		}
		else
		{
			int h = Player.health;
			if ( h > 100 ) {
				h = 100;
			}
			if ( h < 0 ) {
				h = 0;
			}
			pic = mugshotnames[ 3*((100-h)/16)+Player.faceframe ];
		}
	}
	else
	{
		pic = mugshotnames[ 21 ];
	}

	iphoneDrawPic( x, y, w, h, pic );
		
	// blend the right / left damage indicators on the side
	for ( i = 0 ; i < 2 ; i++ ) {
		float	f;
		if ( attackDirTime[i] == 0 ) {
			continue;
		}
		f = iphoneFrameNum - attackDirTime[i];
		if ( f > 30 ) {
			attackDirTime[i] = 0;
			continue;
		}
		if ( f < 20 ) {
			f = 1.0;
		} else {
			f = ( 30 - f ) * 0.1;
		}
		pfglColor4f( 1, 1, 1, f );
		if ( i == 0 ) {
			iphoneDrawPic( 240 - 64, 320 - 80, 40, 80, "iphone/L_damage.tga" );
		} else {
			iphoneDrawPic( 240 + 64 - 40, 320 - 80, 40, 80, "iphone/R_damage.tga" );
		}
		pfglColor4f( 1, 1, 1, 1 );
	}
	
	// draw the tiny health numbers on top of the face
	iphoneDrawNumber( 240, 304, Player.health, 16, 16 );
}

/*
 ==================
 iphoneSetNotifyText
 
 Notify text is a single centered line for "got a key", "found a secret", etc
 ==================
 */
char	notifyText[128];
int		notifyFrameNum;
void iphoneSetNotifyText( const char *str, ... ) {
	va_list		argptr;

	va_start( argptr, str );
	(void)vsnprintf( notifyText, sizeof( notifyText )-1, str, argptr );
	va_end( argptr );

	notifyFrameNum = iphoneFrameNum;
}

void iphoneDrawNotifyText() {
	if ( notifyFrameNum == 0 ) {
		return;
	}
	// display for three seconds, then fade over 0.3
	float f = iphoneFrameNum - notifyFrameNum - 80;
	if ( f < 0 ) {
		f = 1.0;
	} else {
		f = 1.0 - f * 0.1f;
		if ( f < 0 ) {
			notifyFrameNum = 0;
			return;
		}
	}
	
	pfglColor4f( 1, 1, 1, f );
	iphoneCenterText( 240, 5, notifyText );
	pfglColor4f( 1, 1, 1, 1 );
}
#endif

void iphoneStartBonusFlash() {
	bonusFrameNum = iphoneFrameNum;
}

void iphoneStartDamageFlash( int damage ) {
	damageflash += damage;
	if ( damageflash > 64 ) {
		damageflash = 64;
	}
	if ( damageflash < 10 ) {
		damageflash = 10;
	}
}

/*
 ==================
 iphoneSetAttackDirection
 
 +1 = attacked from the left
 -1 = attacked from the right
 ==================
 */
void iphoneSetAttackDirection( int dir ) {
	if ( dir > 0 ) {
		attackDirTime[0] = iphoneFrameNum;
	}
	if ( dir < 0 ) {
		attackDirTime[1] = iphoneFrameNum;
	}
}

#if 0
void iphoneDrawHudControl( hudPic_t *hud ) {
	if ( hud->hudFlags & HF_DISABLED ) {
		return;
	}
	iphoneHighlightPicNumWhenTouched( hud->x, hud->y, hud->width, hud->height, hud->glTexNum );
}

int iphoneDrawHudButton( hudPic_t *hud ) {
	if ( hud->hudFlags & HF_DISABLED ) {
		return 0;
	}
	iphoneDrawHudControl( hud );
	return TouchReleased( hud->x, hud->y, hud->width, hud->height );
}

void iphoneUpdateMapView() {
#ifdef ALLOW_MAP_VIEW_HUD		
	if ( huds.mapView.hudFlags & HF_DISABLED ) {
		return;
	}
	R_Bind( huds.mapView.glTexNum );
	int playerx = Player.position.origin[0] / (float)TILEGLOBAL;
	int playery = Player.position.origin[1] / (float)TILEGLOBAL;
	
	for ( int j = 0; j < 16; j++ ) {
		int y = ( ( iphoneFrameNum << 4 )  + j ) & 63;
		int disty = playery - y;
		GLubyte row[ 64 * 4 ];
		for( int x = 0 ; x < 64; ++x ) {
			int distx = playerx - x;
			if ( distx >= -1 && distx <= 1 && disty == 0 ) {
				row[ x * 4 + 0 ] = 255;
				row[ x * 4 + 1 ] = 255;
				row[ x * 4 + 2 ] = 255;
				row[ x * 4 + 3 ] = 255;
			} else if ( disty >= -1 && disty <= 1 && distx == 0 ) {
				row[ x * 4 + 0 ] = 255;
				row[ x * 4 + 1 ] = 255;
				row[ x * 4 + 2 ] = 255;
				row[ x * 4 + 3 ] = 255;
			} else if ( r_world->tilemap[ x ][ y ] & ( WALL_TILE | PUSHWALL_TILE ) || ! r_world->tileEverVisible[ x ][ y ] ) {
				row[ x * 4 + 0 ] = 0;
				row[ x * 4 + 1 ] = 0;
				row[ x * 4 + 2 ] = 0;
				row[ x * 4 + 3 ] = 0;
			} else {
				row[ x * 4 + 0 ] = 0;
				row[ x * 4 + 1 ] = 0;
				row[ x * 4 + 2 ] = 0;
				row[ x * 4 + 3 ] = 255;
			}
		}
		pfglTexSubImage2D(GL_TEXTURE_2D, 0, 0, 63 - y, 64, 1, GL_RGBA, GL_UNSIGNED_BYTE, row );
	}
#endif	
}

void iphoneDrawMapView() {
#ifdef ALLOW_MAP_VIEW_HUD		
	iphoneDrawHudControl( &huds.mapView );
#endif
}
#endif

/*
==================
iphoneFrame

==================
*/
void iphoneFrame() {
	
	iphoneFrameNum++;
	loggedTimes[iphoneFrameNum&(MAX_LOGGED_TIMES-1)].enterFrame = Sys_Milliseconds();

	[[JWAnimator animator] animate];
	
	// toggle / scroll down the console
	Client_Screen_RunConsole();

	// check for flipping the phone orientation
	iphoneCheckForLandscapeReverse();
	
	// Nobble the console - I've done something that broke it.
	if ( 0 && consoleActive ) {	
		iphoneSet2D();	

		Client_Screen_DrawConsole();	
		
		iphoneSavePrevTouches();
		SysIPhoneSwapBuffers();
		return;
	}
	if ( menuState != IPM_GAME && menuState != IPM_INTERMISSION) {
		iphoneSet2D();
		
		//iphoneDrawMenus();
	
		iphoneSavePrevTouches();
		SysIPhoneSwapBuffers();
		return;
	}

	//------------------
	// normal gameplay
	//------------------

	if( Player.playstate != ex_dead )
	{
		CreateIphoneUserCmd();
		Player.position.angle = NormalizeAngle(Player.position.angle);
	}
	
	// clear depth buffer
	qglDepthMask( GL_TRUE );
	pfglClear( GL_DEPTH_BUFFER_BIT );

	// fill the floor and ceiling
	pfglDisable( GL_BLEND );
	pfglDisable( GL_DEPTH_TEST );
	pfglMatrixMode( GL_MODELVIEW );
    pfglLoadIdentity();
	pfglMatrixMode( GL_PROJECTION );
    pfglLoadIdentity();
	iphoneRotateForLandscape();
	pfglOrtho( 0, 480, 320, 0, -99999, 99999 );

	qglClearColor(sky[0], sky[1], sky[2], 1.0f);
	qglClear(GL_COLOR_BUFFER_BIT);
	

	
	// setup to draw the 3D world 
	float cur_x_fov, cur_y_fov; // x & y field of view (in degrees)
	float ratio; // viewport width/height
	ratio = (float) viddef.width / (float)viddef.height; // FIXME: move somewhere
	cur_x_fov = 75;
	cur_y_fov = CalcFov( cur_x_fov, (float)viddef.width, (float)viddef.height );
	
	pfglMatrixMode( GL_PROJECTION );
	pfglLoadIdentity();
	iphoneRotateForLandscape();
	MYgluPerspective( cur_y_fov - 2.0f, ratio, 0.2f, 90.0f );	// tweak fov in to avoid edge tile clips
	pfglMatrixMode( GL_MODELVIEW );
	pfglLoadIdentity();
	
	JWLandscape* landscape = (JWLandscape*)[[[JWManagers sharedManager] managerOfClass:[JWLandscapeManager class]] entity];

	if(menuState == IPM_GAME) {
		// In game.
		float azimuth = FINE2DEG(Player.position.azimuth);
		//NSLog(@"%d, %f", Player.position.azimuth, azimuth);
		if(azimuth > kothPlayerMaxAzimuth) {
			azimuth = kothPlayerMaxAzimuth;
		} else if(azimuth < kothPlayerMinAzimuth) {
			azimuth = kothPlayerMinAzimuth;
		}
		
		pfglRotatef( azimuth, 1, 0, 0 );
		pfglRotatef( (float)(90 - FINE2DEG( Player.position.angle )), 0, 1, 0 );
		Player.position.azimuth = DEG2FINE(azimuth);
		
		pfglTranslatef( -Player.position.origin[ 0 ] - 0.5, -Player.position.height, Player.position.origin[ 1 ] - 0.5);
	} else if(menuState == IPM_INTERMISSION) {
		// Spinny landscape.
		static float theta = 0.0f;
		float radius = [landscape size];
		float xAxis = [landscape dimensions].height;
		float zAxis = [landscape dimensions].width;
		
		float x = -radius * sin(DEG2RAD(theta)) + xAxis / 2.0f;
		float z = radius * cos(DEG2RAD(theta)) + zAxis / 2.0f;
		pfglRotatef( 30.0f, 1.0f, 0.0f, 0.0f ); // Azimuth
		
		pfglRotatef( theta, 0, 1, 0 ); // Rotation
		pfglTranslatef(-x, -(5.0f * radius / 8.0f)  , -z); // Camera position
		
		
		wolf3dAppDelegate* appDelegate = (wolf3dAppDelegate*)[UIApplication sharedApplication].delegate;		
		NSInteger frameInterval = appDelegate.glView.displayLink.frameInterval;
		CFTimeInterval duration = appDelegate.glView.displayLink.duration;
		CFTimeInterval framesPerSecond = 1.0 / (frameInterval * duration);
		
		// Increment such that it takes ROTATION_TIME seconds to do one spin of the landscape.
		static float ROTATION_TIME = 10.0f;
		float deltaTheta = 360.0f / framesPerSecond / ROTATION_TIME;
		
		theta += deltaTheta;
		if(theta > 360.0f) {
			theta -= 360.0f;
		}
	}
	
	pfglCullFace( GL_BACK );
	
	pfglEnable( GL_DEPTH_TEST );
	pfglEnable( GL_CULL_FACE );
	pfglDisable( GL_BLEND );
	pfglDisable( GL_ALPHA_TEST );
	
	
#if 1	
	// Lighting.
	qglPushMatrix();
	{
		qglTranslatef(16.0f, 20.0f, 16.0f);
		GLfloat position[] = {0, 0, 0, 1};
		qglLightfv(GL_LIGHT0, GL_POSITION, position);
	}
	qglPopMatrix();

	// Sentinel work.
	if(menuState == IPM_GAME && [JWAnimator animator].animationFrames == 0) {
		static NSUInteger currentSentinel = 0;
		JWSentinelManager* sentinelManager = (JWSentinelManager*)[[JWManagers sharedManager] managerOfClass:[JWSentinelManager class]];
		NSArray* sentinels = sentinelManager.sentinels;
		if(currentSentinel < [sentinels count]) {
			JWSentinel* sentinel = [sentinels objectAtIndex:currentSentinel];
			
			// Don't do meanie's work here.
			if(sentinel.sentinelId != 666) {
				[sentinel doWork];
			}
		}
		currentSentinel++;
		currentSentinel %= MAX_SENTINELS;
	}
	
	// Player picks.
	if(numPrevTouches == 1 && (swipe[0] == 0 && swipe[1] == 0)) {
		//NSLog(@"Touch");
		CGPoint point;
		point.x = touches[0][0];
		point.y = touches[0][1];
		JWSquare* square = [[JWPicker picker] pickUsingScreenCoordinates:point];
		
		if(square) {
			landscape.selectedSquare.selected = NO;
			landscape.selectedSquare = square;
			[square setSelected:YES];
		}
	}
	
	// Draw scene.
	NSEnumerator* enumerator = [[[JWManagers sharedManager] managers] objectEnumerator];
	NSObject<JWManager>* m = nil;
	
	while(m = [enumerator nextObject]) {
		[m draw];
		[m postDraw];
	}
#endif
#if 0	
	// blend in the sprites
	R_DrawSprites();
#endif
	// draw 2D overlays
	iphoneSet2D();	
	
	// Do a full screen blend for death, warning and sentinel attack.
	char blendColor[4] = {0};
	if(Player.health == -1) {
		static int deathFadeIntensity = 0;
		
		if(deathFadeIntensity == 0) {
			[(wolf3dAppDelegate *)[UIApplication sharedApplication].delegate hideGameScreen:YES];
		}
		
		blendColor[0] = 0;
		blendColor[1] = 0;
		blendColor[2] = 0;
		blendColor[3] = deathFadeIntensity;
		deathFadeIntensity += 2;
		if( deathFadeIntensity >= 240 ) {
			deathFadeIntensity = 0;
			wolf3dAppDelegate* appDelegate = (wolf3dAppDelegate*)[UIApplication sharedApplication].delegate;
			blendColor[3] = 0;
			[appDelegate playerDied];
		}
	} else {
		if([JWSentinel dangerMask]) {
			blendColor[0] = 255;
			blendColor[1] = 0;
			blendColor[2] = 0;
			blendColor[3] = 128;
		} else if([JWSentinel warningMask]) {
			blendColor[0] = 255;
			blendColor[1] = 255;
			blendColor[2] = 0;
			blendColor[3] = 128;
		}
	}
	if ( blendColor[3] != 0 && blends->value != 0 ) {
		R_DrawBox(0, 0, viddef.width, viddef.height, *(int *)blendColor);
	}
	
#if 0
	iphoneDrawNotifyText();

	iphoneDrawMapView();

	iphoneDrawFace();	

	iphoneDrawNumber( huds.ammo.x + huds.ammo.width / 2, huds.ammo.y, Player.ammo[AMMO_BULLETS], 48, 48 );
	
	if ( hideControls->value != 1 ) {
		iphoneDrawHudControl( &huds.forwardStick );
		iphoneDrawHudControl( &huds.sideStick );
		iphoneDrawHudControl( &huds.turnStick );
		//iphoneDrawHudControl( &huds.fire );
	}

	if ( iphoneDrawHudButton( &huds.menu ) ) {
		menuState = IPM_MAIN;
	}
	if ( iphoneDrawHudButton( &huds.map ) ) {
		iphoneOpenAutomap();
	}
#endif		
	
	Client_Screen_DrawConsole();	
	iphoneSavePrevTouches();
	SysIPhoneSwapBuffers();	// do the swapbuffers
}
